#include "include/customshortcut.h"

namespace
{

	const char* UnboundShortcut = "<unbound>";
	const char* AnonymousAction = "<anonymous action>";
	const char* AnonymousShortcut = "<anonymous shortcut>";

	template <class T>
	bool trySetSequence(QObject* obj, void (T::*setter)(const QKeySequence&), QKeySequence (T::*getter)() const, QKeySequence sequence)
	{
		T* dest = qobject_cast<T*>(obj);
		if (dest == 0)
			return false;

		if ((dest->*getter)() != sequence)
			(dest->*setter)(sequence);

		return true;
	}

	bool trySetActionShortcut(QObject* obj, const QKeySequence& sequence)
	{
		return trySetSequence(obj, &QAction::setShortcut, &QAction::shortcut, sequence);
	}

	bool trySetShortcutKey(QObject* obj, const QKeySequence& sequence)
	{
		return trySetSequence(obj, &QShortcut::setKey, &QShortcut::key, sequence);
	}


} //private namespace

CustomShortcut::CustomShortcut(const QString& tag, QObject *parent) :
	QObject(parent)
	, _tag(tag)
	, _activeSequence(CustomShortcut::DefaultSequence)
	, _boundObject(0)
{
}


QString CustomShortcut::tag() const
{
	return _tag;
}

void CustomShortcut::setTag(const QString& value)
{
	_tag = value;
}

QKeySequence CustomShortcut::defaultSequence() const
{
	return _defaultSequence;
}

QKeySequence CustomShortcut::customSequence() const
{
	return _customSequence;
}


void CustomShortcut::setCustomSequence(const QKeySequence& value)
{
	_customSequence = value;

	applyActiveSequence();
}


void CustomShortcut::bindTo(QAction* action)
{
	_defaultSequence = action->shortcut();
	_boundObject = action;

	applyActiveSequence();
}


void CustomShortcut::bindTo(QShortcut* shortcut)
{
	_defaultSequence = shortcut->key();
	_boundObject = shortcut;

	applyActiveSequence();
}

QString CustomShortcut::text() const
{
	QAction* action = qobject_cast<QAction*>(_boundObject);
	if (action != 0)
		return !action->text().isEmpty() ? action->text() : tr(AnonymousAction);

	QShortcut* shortcut = qobject_cast<QShortcut*>(_boundObject);
	if (shortcut != 0)
		return !shortcut->whatsThis().isEmpty() ? shortcut->whatsThis() : tr(AnonymousShortcut);

	return tr(UnboundShortcut);
}

CustomShortcut::ActiveSequence CustomShortcut::activeSequence() const
{
	return _activeSequence;
}

void CustomShortcut::setActiveSequence(CustomShortcut::ActiveSequence value)
{
	_activeSequence = value;
	applyActiveSequence();
}


QKeySequence CustomShortcut::sequence() const
{
	return _activeSequence == CustomShortcut::CustomSequence ? customSequence() : defaultSequence();
}


void CustomShortcut::setSequence(const QKeySequence& value)
{
	if (value == _defaultSequence)
	{
		_activeSequence = CustomShortcut::DefaultSequence;
		_customSequence = QKeySequence();
	}
	else
	{
		_activeSequence = CustomShortcut::CustomSequence;
		_customSequence = value;
	}

	applyActiveSequence();
}


void CustomShortcut::applyActiveSequence()
{
	QKeySequence seq = sequence();
	trySetActionShortcut(_boundObject, seq) || trySetShortcutKey(_boundObject, seq);
}
